package com.JL.engine;

import com.JL.engine.components.ViewComponent;
import com.JL.engine.model.Component;
import com.JL.engine.model.Entity;
import com.JL.engine.util.LocalTimeUtil;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

public class GameWorld extends JPanel {
    //存储游戏世界中所有的实体对象
    private final ConcurrentLinkedQueue<Entity> ENTITIES = new ConcurrentLinkedQueue<>();

    private LocalTimeUtil localTimeUtil = new LocalTimeUtil();

    /*将实体添加到游戏世界中
    * 形参： entity - 游戏实体
    * */

    public void addEntity(Entity entity){
        entity.setGameWorld(this);
        ENTITIES.add(entity);
        entity.onAdded();
    }

    /*将实体从游戏世界中移除
     * 形参： entity - 游戏实体
     * */
    public void removeEntity(Entity entity){
        ENTITIES.remove(entity);
        entity.onRemoved();
    }

    public List<Entity> getEntitiesByComponent(Class<? extends Component> componentClass){
        List<Entity> entities = new ArrayList<>();
        for(Entity entity : ENTITIES){
            List<Component> components = entity.getComponents();
            for(Component component : components){
                // 检测component对象是否与componentClass兼容（类型一致，或者是子类）
                if(componentClass.isAssignableFrom(component.getClass())){
                    entities.add(entity);
                }
            }
        }
        return entities;
    }

    // 绘制界面，由JDK自动调用
    @Override
    protected void paintComponent(Graphics g){
        // 清屏
        g.clearRect(0, 0, getWidth(),getHeight());
        // 调用所有实体中的组件的update方法
        // 获取当前帧消耗的毫秒数，并且将其转换为秒
        double tpf = localTimeUtil.getTimeConsumed() / 1000;

        for(Entity entity : ENTITIES){
            entity.update(tpf);
        }
        List<Entity> entities = getEntitiesByComponent(ViewComponent.class);
        for(Entity entity : entities){
            ViewComponent component = entity.getComponent(ViewComponent.class);
            component.draw(g);
        }
        localTimeUtil.reset();
        // 告知系统重新绘制界面（会再次调用piantComponent方法）
        this.repaint();
    }
}
